package cn.wolfcode.wolf2w.business.service.impl;

import cn.wolfcode.wolf2w.business.api.RemoteDestinationService;
import cn.wolfcode.wolf2w.business.api.domain.Note;
import cn.wolfcode.wolf2w.business.api.domain.NoteContent;
import cn.wolfcode.wolf2w.business.api.domain.Note;
import cn.wolfcode.wolf2w.business.mapper.NoteMapper;
import cn.wolfcode.wolf2w.business.query.NoteQuery;
import cn.wolfcode.wolf2w.business.service.INoteContentService;
import cn.wolfcode.wolf2w.business.service.INoteService;
import cn.wolfcode.wolf2w.business.util.DateUtil;
import cn.wolfcode.wolf2w.common.core.constant.SecurityConstants;
import cn.wolfcode.wolf2w.common.core.context.SecurityContextHolder;
import cn.wolfcode.wolf2w.common.redis.service.RedisService;
import cn.wolfcode.wolf2w.common.redis.util.RedisKeys;
import cn.wolfcode.wolf2w.member.api.RemoteUserInfoService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 旅游日记Service业务层处理
 *
 * @author dh
 * @date 2025-09-16
 */
@Service
@Transactional
public class NoteServiceImpl extends ServiceImpl<NoteMapper,Note> implements INoteService {


    @Autowired
    private RemoteDestinationService remoteDestinationService;
    @Autowired
    private INoteContentService noteContentService;
    @Autowired
    private RedisService redisService;
    @Override
    public IPage<Note> queryPage(NoteQuery qo) {


        IPage<Note> page = new Page<>(qo.getCurrentPage(), qo.getPageSize());
        QueryWrapper<Note> wrapper = new QueryWrapper<>();

        if ("create_time".equals(qo.getOrderBy())){
            wrapper.orderByDesc("create_time");
        }
        if ("viewnum".equals(qo.getOrderBy())){
            wrapper.orderByDesc("viewnum");
        }
        /**
         * 出发时间
         * 月份的高级查询
         * wrapper.apply()是自定义查询条件
         */
        switch (qo.getTravelTimeType()){
            case 1:
                wrapper.apply("MONTH(travel_time) IN (1, 2)");
                break;
            case 2:
                wrapper.apply("MONTH(travel_time) IN (3, 4)");
                break;
            case 3:
                wrapper.apply("MONTH(travel_time) IN (5, 6)");
                break;
            case 4:
                wrapper.apply("MONTH(travel_time) IN (7, 8)");
                break;
            case 5:
                wrapper.apply("MONTH(travel_time) IN (9, 10)");
                break;
            case 6:
                wrapper.apply("MONTH(travel_time) IN (11, 12)");
                break;
            default:
                break;
        }
        /**
         * 人均花费的高级查询
         */
        switch (qo.getConsumeType()){
            case 1:
                wrapper.between("avg_consume",1,999);
                break;
            case 2:
                wrapper.between("avg_consume",1000,6000);
                break;
            case 3:
                wrapper.between("avg_consume",6000,20000);
                break;
            case 4:
                wrapper.apply("avg_consume > 20000");
                break;
            default:
                break;
        }

        /**
         *  出行天数的高级查询
         */
        switch (qo.getDayType()){
            case 1:
                wrapper.apply("days < 3");
                break;
            case 2:
                wrapper.between("days",4,7);
                break;
            case 3:
                wrapper.between("days",8,14);
                break;
            case 4:
                wrapper.apply("days > 15");
                break;
            default:
                break;
        }
        return baseMapper.selectPage(page,wrapper);
    }

    /**
     * 游记右侧 相关游记
     * @param destId
     * @return
     */
    @Override
    public List<Note> viewnnumTop3(Long destId) {
        List<Note> list = lambdaQuery()
                .eq(Note::getDestId, destId)
                .orderByDesc(Note::getViewnum)
                .last("limit 3")
                .list();
        return list;
    }

    @Transactional
    @Override
    public void add(Note note) {
        Note note1 = new Note();

        note1.setDestId(note.getDestId());

        String name = remoteDestinationService.getOne(note.getDestId(), SecurityConstants.INNER).getData().getName();
        note1.setDestName(name);

        note1.setAuthorId(SecurityContextHolder.getUserId());

        note1.setTitle(note.getTitle());

        note1.setSummary(note.getSummary());
        note1.setCoverUrl(note.getCoverUrl());
        note1.setTravelTime(note.getTravelTime());
        note1.setAvgConsume(note.getAvgConsume());
        note1.setDays(note.getDays());
        note1.setPerson(note.getPerson());
        note1.setIsPublic(note.getIsPublic().equals("true") ? "1" : "0");
        note1.setViewnum(0l);
        note1.setReplynum(0l);
        note1.setFavornum(0l);
        note1.setSharenum(0l);
        note1.setThumbsupnum(0l);
        note1.setStatus("0");
        note1.setCreateTime(new Date());
        baseMapper.insert(note1);
        //插入内容表
        Long id = note1.getId();
        NoteContent noteContent = new NoteContent();
        noteContent.setId(id);
        noteContent.setContent(note.getContentStr());
        noteContentService.save(noteContent);

    }

    @Override
    public Map<String, Object> star(Long id) {
        //注入id
        Long userId = SecurityContextHolder.getUserId();
        //拼key
        String key = RedisKeys.USER_NOTE_THUMBSUP.join(id.toString(), userId.toString());
        //计算过期时间
        Date begin = new Date();
        Date end = DateUtil.getEndDate(begin);
        long ttl = DateUtil.getDateBetween(begin, end);

        if (! redisService.hasKey(key)){
            redisService.setCacheObject(key,0,ttl, TimeUnit.SECONDS);
        }
        //点赞次数++做判断
        Long count = redisService.incrementCacheObjectValue(key, 1);
        String hashkey = RedisKeys.NOTE_STATIS_HASH.join(id.toString());
        Boolean result = false;
        //判断点赞次数,返回合适的result
        if (count <= 3){
            result = true;
            //真实的点赞次数加1
            redisService.incrementCacheMapValue(hashkey,"thumbsupnum",1);
        }
        //将result添加到map中
        Map<String, Object> cacheMap = redisService.getCacheMap(hashkey);
        cacheMap.put("result",result);
        //返回map
        return cacheMap;
    }

    @Override
    public void statisCondition() {
        String hashKey = RedisKeys.NOTE_STATIS_HASH.join("*");
        Collection<String> map = redisService.keys(hashKey);
        if (! map.isEmpty() && map.size() > 0){
            for (String key : map) {
                Map<String, Object> cacheMap = redisService.getCacheMap(key);
                lambdaUpdate()
                        .eq(Note::getId,cacheMap.get("id"))
                        .set(Note::getViewnum,cacheMap.get("viewnum"))
                        .set(Note::getReplynum,cacheMap.get("replynum"))
                        .set(Note::getFavornum,cacheMap.get("favornum"))
                        .set(Note::getSharenum,cacheMap.get("sharenum"))
                        .set(Note::getThumbsupnum,cacheMap.get("thumbsupnum"))
                        .update();
            }
        }
    }

    @Override
    public Map<String, Object> collect(Long id) {
        Long userId = SecurityContextHolder.getUserId();
        String key = RedisKeys.USER_NOTE_FAVOR.join(String.valueOf(userId));
        //如果用户没有收藏并且没有该用户对应的key,创建用户对应的id存入到ids
        if (! redisService.hasKey(key)){
            Set<Long> ids = new HashSet<>();
            //redis删除set不保留set空集合结构,存一个-1l防止set为空
            ids.add(-1l);
            redisService.setCacheSet(key,ids);
        }
        boolean b = false;
        String hashkey = RedisKeys.NOTE_STATIS_HASH.join(String.valueOf(id));
        if (redisService.isCacheSetContains(key,id)){
            //取消收藏
            redisService.deleteCacheSetValue(key,id);
            redisService.incrementCacheMapValue(hashkey,"favornum",-1);
        }else {
            //添加收藏
            redisService.addCacheSetValue(key,id);
            redisService.incrementCacheMapValue(hashkey,"favornum",1);
            b = true;
        }
        Map<String, Object> cacheMap = redisService.getCacheMap(hashkey);
        cacheMap.put("result",b);

        return cacheMap;
    }

    @Override
    public Boolean isUserFavor(Long uid, Long nid) {
        String key = RedisKeys.USER_NOTE_FAVOR.join(String.valueOf(uid));
        //如果用户没有收藏并且没有该用户对应的key,创建用户对应的sid存入到sids
        if (! redisService.hasKey(key)){
            Set<Long> nids = new HashSet<>();
            //redis删除set不保留set空集合结构,存一个-1l防止set为空
            nids.add(-1l);
            redisService.setCacheSet(key,nids);
        }
        return redisService.isCacheSetContains(key,nid);

    }

    @Override
    public Map<String, Object> viewnumIncr(Long sid) {
        String key = getKey(sid);
        redisService.incrementCacheMapValue(key,"viewnum",1);
        Map<String, Object> cacheMap = redisService.getCacheMap(key);
        return cacheMap;
    }

    private String getKey(Long noteId) {
        String key = RedisKeys.NOTE_STATIS_HASH.join(noteId.toString());
        if ( ! redisService.hasKey(key)){
            Note note = this.getById(noteId);
            HashMap<String, Object> map = new HashMap<>();
            map.put("viewnum", Integer.valueOf(note.getViewnum().toString()));
            map.put("replynum", Integer.valueOf(note.getReplynum().toString()));
            map.put("sharenum", Integer.valueOf(note.getSharenum().toString()));
            map.put("favornum", Integer.valueOf(note.getFavornum().toString()));
            map.put("thumbsupnum", Integer.valueOf(note.getThumbsupnum().toString()));
            map.put("id",Integer.valueOf(note.getId().toString()));
            redisService.setCacheMap(key,map);
        }
        return key;
    }
}
